package agent;
import java.util.ArrayList;
import java.util.Hashtable;

import dao.DaoAgente;

import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.Behaviour;
import jade.core.behaviours.OneShotBehaviour;
import jade.core.behaviours.SequentialBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import model.Coordenada;
import model.Rota;
import model.Shape;
import model.Stop;
import model.SubRota;



public class AgBuscador extends Agent{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Coordenada origem;
	private Coordenada destino;
	private Stop stopOrigem;
	
	
	
	protected void setup(){
		
		
		
		SequentialBehaviour seq = new SequentialBehaviour(this){//composto
			private static final long serialVersionUID = 1L;
			
	
		}; //fim do composto
		
		seq.addSubBehaviour(new OneShotBehaviour(this){ //Comportamento registra serviço
			private static final long serialVersionUID = 1L;

			@Override
			public void action() {
				//Criando entrada no DF
				DFAgentDescription dfd = new DFAgentDescription();
				dfd.setName(getAID());
				
				//Criando serviço
				ServiceDescription sd = new ServiceDescription();
				sd.setType("busca");
				sd.setName("buscarota");
				
				//Adicionando ao dfd
				dfd.addServices(sd);
				try{
					DFService.register(myAgent, dfd);
				}catch(FIPAException e){
					e.printStackTrace();
				}
				
			}
			
		}); //fim do registra serviço
		
		seq.addSubBehaviour(new Behaviour(this){ //recebe mensagen com os dados da busca
			
			private static final long serialVersionUID = 1L;
			Hashtable obj; 
			public void action(){
				block();
				System.out.println("Exec comportamento...RECEBE MSG "+myAgent.getName());
				ACLMessage msg = receive();
				if(msg !=null){
					try{
						obj = new Hashtable();
						obj =  (Hashtable) msg.getContentObject();
						origem = (Coordenada) obj.get("origem");
						destino = (Coordenada) obj.get("destino");
						stopOrigem = (Stop) obj.get("stopOrigem");
						
						System.out.println("Agente "+myAgent.getName()+"Recebeu stop num:" +stopOrigem.getStop_id());
					}catch(Exception e){
						e.printStackTrace();
					}
				}
			}
			
			public boolean done(){
				if(this.obj != null){
					try{
						DFService.deregister(myAgent);
					}catch(FIPAException e){
						e.printStackTrace();
					}
					return true;
				}else{
					return false;
				}
			}
		});//fim do recebe mensagem
				
		
		seq.addSubBehaviour(new Behaviour(this){  //Comportamento busca rotas
			
			private static final long serialVersionUID = 1L;
			ArrayList<Rota> rotas = new ArrayList<Rota>();
			ArrayList<SubRota> subRotas = new ArrayList<SubRota>();
			Stop stopDestino = new Stop();
	
			@Override
			public void action() {
				System.out.println("Exec comportamento...bUSCA ROTA"+myAgent.getName());
				rotas = buscar(origem, destino, stopOrigem, stopDestino, subRotas);
				
				System.out.println("Numero de rotas devolvidas pela função: "+rotas.size());
				System.out.println("Adicionar rotas ----------"+myAgent.getName());
				for(int i = 0; i<rotas.size(); i++){
					System.out.println("Adicionar rota num:"+i+" na área por "+myAgent.getName());
					AreaRotas.addRota(rotas.get(i));
					
				}
				
				//adicionando contagem de buscas
				AreaRotas.addNumBuscas();
				
				System.out.println("Numero de ROTAS na área: "+AreaRotas.getNumRotas());
				System.out.println("Numero de BUSCAS na área: "+AreaRotas.getNumBuscas());
			}

			@Override
			public boolean done() {

				return true;
			}
			
			public ArrayList<Rota> buscar(Coordenada origem, Coordenada destino, Stop stopOrigem, Stop stopDestino, ArrayList<SubRota> subRotas){

				int raioDestino = 0;
				ArrayList<String> trips = new ArrayList<String>();
				boolean raioDestinoTocou = false;
				DaoAgente dao = new DaoAgente();
				double distDestOrig = destino.calculaDistancia(origem.getLat(), origem.getLon());
				
					
		
				while(trips.size() == 0){
					
					raioDestino++;
					trips = dao.getTripsOfStopCoordRaio(stopOrigem.getStop_id(), destino.getLat(), destino.getLon(), raioDestino);
				}
					
				for(int t = 0; t < trips.size(); t++){
					int raioShape = 0;
					//ArrayList<Stop> stopsOrigem = new ArrayList<Stop>();
					ArrayList<Stop> stopsDestino = new ArrayList<Stop>();
					ArrayList<Shape> forma = new ArrayList<Shape>();
					Shape shapeOrigem = new Shape();
					Shape shapeDestino = new Shape();
					SubRota srt = new SubRota();
					if(raioDestinoTocou)
						break;
					stopOrigem = dao.getStopOfTripStopId(trips.get(t), stopOrigem.getStop_id());
							
					//pegando stops no destino, da viagem de indice t
					stopsDestino = dao.getStopsOfCoordRaio(trips.get(t), destino.getLat(), destino.getLon(), raioDestino);
					
					
					//testando se raio tocou
					for(int i = 0; i < stopsDestino.size(); i++){
						if(stopOrigem.getStop_id() == stopsDestino.get(i).getStop_id()){
							raioDestinoTocou = true;
							break;
						}
					}
					
					if(raioDestinoTocou)
						break;
					
								
					//eliminando os stops do destino de direção contraria
					ArrayList<Stop> stopsDestinoTemp = new ArrayList<Stop>();
					for(int i = 0; i < stopsDestino.size(); i++){
						if(stopOrigem.getStop_sequence() < stopsDestino.get(i).getStop_sequence()){
							stopsDestinoTemp.add(stopsDestino.get(i));
						}
					}
					if(stopsDestinoTemp.size() == 0){
						continue;
					}
					else{
						stopsDestino = stopsDestinoTemp;
						//identificando o stop mais próximo do destino
						stopDestino = stopsDestino.get(0);
						double distStopDestino;
						double distStopDestinoTeste;
						for(int i = 0; i < stopsDestino.size(); i++){
							distStopDestino = destino.calculaDistancia(stopDestino.getStop_lat(), stopDestino.getStop_lon());
							distStopDestinoTeste = destino.calculaDistancia(stopsDestino.get(i).getStop_lat(), stopsDestino.get(i).getStop_lon());
							if(distStopDestinoTeste < distStopDestino){
								stopDestino = stopsDestino.get(i);
							}
						}
						double distDestStDest = destino.calculaDistancia(stopDestino.getStop_lat(), stopDestino.getStop_lon());
						if(distDestStDest > distDestOrig){
							continue;
						}
									
						//Aqui já tenho "stopOrigem" e "stopDestino" com linha viagem.
						
						
						///buscando Shapes de origem
						ArrayList<Shape> shapesOrigem = new ArrayList<Shape>();
						for(raioShape = 1; shapesOrigem.size() == 0; raioShape++){
							shapesOrigem = dao.getShapesOfTripCoordRaio(trips.get(t), stopOrigem.getStop_lat(), stopOrigem.getStop_lon(), raioShape);
						}
						
						//encontrando shape mais pròximo do stop de Origem
						Coordenada coordStopOrig = new Coordenada(stopOrigem.getStop_lat(), stopOrigem.getStop_lon());
						shapeOrigem = shapesOrigem.get(0);
						double distShapeOrigem;
						double distShapeOrigemTeste;
						for(int i = 0; i < shapesOrigem.size(); i++){
							distShapeOrigem = coordStopOrig.calculaDistancia(shapeOrigem.getShape_pt_lat(), shapeOrigem.getShape_pt_lon());
							distShapeOrigemTeste = coordStopOrig.calculaDistancia(shapesOrigem.get(i).getShape_pt_lat(), shapesOrigem.get(i).getShape_pt_lon());
							if(distShapeOrigemTeste < distShapeOrigem){
								shapeOrigem = shapesOrigem.get(i);
							}
						}
						
						
						
						///buscando Shapes de Destino
						ArrayList<Shape> shapesDestino = new ArrayList<Shape>();
						for(raioShape = 1; shapesDestino.size() == 0; raioShape++){
							shapesDestino = dao.getShapesOfTripCoordRaio(trips.get(t), stopDestino.getStop_lat(), stopDestino.getStop_lon(), raioShape);
						}
						
						//encontrando shape mais pròximo do stop de Destino
						Coordenada coordStopDest = new Coordenada(stopDestino.getStop_lat(), stopDestino.getStop_lon());
						shapeDestino = shapesDestino.get(0);
						double distShapeDestino;
						double distShapeDestinoTeste;
						for(int i = 0; i < shapesDestino.size(); i++){
							distShapeDestino = coordStopDest.calculaDistancia(shapeDestino.getShape_pt_lat(), shapeDestino.getShape_pt_lon());
							distShapeDestinoTeste = coordStopDest.calculaDistancia(shapesDestino.get(i).getShape_pt_lat(), shapesDestino.get(i).getShape_pt_lon());
							if(distShapeDestinoTeste < distShapeDestino){
								shapeDestino = shapesDestino.get(i);
							}
						}
						
						///Aqui já tenho "shapeOrigem" e "shapeDestino" com linha viagem.
						
						
						//buscando forma da subrota para ser desenhada
						if(shapeOrigem.getShape_id() == shapeDestino.getShape_id()){
							forma = dao.getShapesOfTripOrigemDestino(shapeOrigem.getShape_id(), shapeOrigem.getShape_pt_sequence(), shapeDestino.getShape_pt_sequence());
						}
						else{
							System.out.println("SHAPE DE ORIGEM ID DIFERENTE DO SHAPE DE DESTINO ID!!!!!");
							continue;
						}
						if(forma.size() > 0){
							System.out.println("Montando SubRota");
							srt.setForma(forma);
							srt.setStopOrigem(stopOrigem);
							srt.setStopDestino(stopDestino);
							srt = dao.preencheSubrota(trips.get(t), srt);
							System.out.println("Add SubRota");
							ArrayList<SubRota> subRotasNova = new ArrayList<SubRota>();
							subRotasNova = subRotas;
							subRotasNova.add(srt);
							
							
							if(raioDestino <= 2){
								Rota rota = new Rota();
								System.out.println("Raio < 2 Add rota");
								rota.setSubrotas(subRotasNova);
								//AreaRotas.addRota(rota);
								rotas.add(rota);
								continue;
							}
							else{
								subRotasNova.add(srt);
								//recurção
								Coordenada novaOrigem = new Coordenada(stopDestino.getStop_lat(), stopDestino.getStop_lon());
								Stop novoStopOrigem = stopDestino;
								Stop novoStopDestino = new Stop();
								System.out.println("Recurção");
								buscar(novaOrigem, destino, novoStopOrigem, novoStopDestino, subRotasNova);
							}
							
						}
						continue;
					}
					
				}
				
				return rotas;
					
			}
			
			
			
			
			public boolean toucouRaio(ArrayList<String> trips, double lat, double lon, int raioDestino, Stop stopOrigem){
				boolean tocaRaio = false;
				DaoAgente dao = new DaoAgente();
				//pegando stops no destino, da viagem de indice t
				for(int t = 0; t < trips.size(); t++){
					ArrayList<Stop> stopsDestino = dao.getStopsOfCoordRaio(trips.get(t), destino.getLat(), destino.getLon(), raioDestino);
					
					//Verificando se o raio destino tocou o stopOrigem
					for(int i = 0; i < stopsDestino.size(); i++){
						
						if((stopOrigem.getStop_lat() == stopsDestino.get(i).getStop_lat()) && (stopOrigem.getStop_lon() == stopsDestino.get(i).getStop_lon())){
							tocaRaio = true;
						}
						
					}
					if(tocaRaio){
						return tocaRaio;
					}
				}
				return tocaRaio;
				
			}

		}); 
		
		
//		seq.addSubBehaviour(new Behaviour(this){ 
//			private static final long serialVersionUID = 1L;
//			
//			private boolean statusMsg = false;
//
//
//			public void action(){
//				//envia mensagem
//				ACLMessage msg = new ACLMessage(ACLMessage.INFORM);
//				msg.addReceiver(new AID("Coordenador", AID.ISLOCALNAME));
//				msg.setContent("terminado");
//				myAgent.send(msg);
//				System.out.print("Env msg msgrecebida > Coordenador");
//				
//				
//				//recebe mensagem de confirmação
//				ACLMessage msg2 = receive();
//				if(msg2 != null){
//					String content = msg2.getContent();
//					if(content.equalsIgnoreCase("msgrecebida")){
//						
//						
//						//REGISTRANDO DENOVO
//						//Criando entrada no DF
//						DFAgentDescription dfd = new DFAgentDescription();
//						dfd.setName(getAID());
//						
//						//Criando serviço
//						ServiceDescription sd = new ServiceDescription();
//						sd.setType("busca");
//						sd.setName("buscarota");
//						
//						//Adicionando ao dfd
//						dfd.addServices(sd);
//						
//						statusMsg = true;
//						try{
//							DFService.register(myAgent, dfd);
//						}catch(FIPAException e){
//							e.printStackTrace();
//						}
//					}
//				}
//				
//			}
//			
//			public boolean done(){
//				return statusMsg;
//			}
//		});
		
		
		seq.addSubBehaviour(new OneShotBehaviour(this){ //Comportamento registra serviço
			private static final long serialVersionUID = 1L;

			@Override
			public void action() {
				//Criando entrada no DF
				DFAgentDescription dfd = new DFAgentDescription();
				dfd.setName(getAID());
				
				//Criando serviço
				ServiceDescription sd = new ServiceDescription();
				sd.setType("busca");
				sd.setName("buscarota");
				
				//Adicionando ao dfd
				dfd.addServices(sd);
				try{
					DFService.register(myAgent, dfd);
				}catch(FIPAException e){
					e.printStackTrace();
				}
				
			}
			
		}); //fim do registra serviço
		
	
		addBehaviour(seq);
		
		
		
//		//Criando entrada no DF
//		DFAgentDescription dfd = new DFAgentDescription();
//		dfd.setName(getAID());
//		
//		//Criando serviço
//		ServiceDescription sd = new ServiceDescription();
//		sd.setType("busca");
//		sd.setName("buscarota");
//		
//		//Adicionando ao dfd
//		dfd.addServices(sd);
//		try{
//			DFService.register(myAgent, dfd);
//		}catch(FIPAException e){
//			e.printStackTrace();
//		}



			
		
	}
	
	protected void takeDown(){
//		System.out.println("Numero de rotas = "+AreaRotas.getNumRotas());
//		ArrayList<Rota> rotas = AreaRotas.getRotas();
//		System.out.println("Rotas: "+rotas.size());
//		for(int i=0; i<rotas.size(); i++){
//			System.out.println("Rota numero: "+(i+1)+"\t\t\tNumero de Subrotas: "+rotas.get(i).getSubrotas().size());
//			for(int j=0; j<rotas.get(i).getSubrotas().size(); j++){
//				System.out.println("Rota numero: "+(i+1)+"\t\t\tSubrota numero: "+(j+1));
//				System.out.println("Stop de origem ID: "+rotas.get(i).getSubrotas().get(j).getStopOrigem().getStop_id());
//				System.out.println("Stop de destino ID: "+rotas.get(i).getSubrotas().get(j).getStopDestino().getStop_id());
//				System.out.println("Origem LAT: "+rotas.get(i).getSubrotas().get(j).getOrigem().getLat()+"\t\t\tOrigem LON: "+rotas.get(i).getSubrotas().get(j).getOrigem().getLon());
//				System.out.println("Destino LAT: "+rotas.get(i).getSubrotas().get(j).getDestino().getLat()+"\t\tDestino LON: "+rotas.get(i).getSubrotas().get(j).getDestino().getLon());
//				System.out.println("Distancia: "+rotas.get(i).getSubrotas().get(j).getDistancia());
//				System.out.println("Viagem: "+rotas.get(i).getSubrotas().get(j).getViagem());
//				System.out.println("Linha: "+rotas.get(i).getSubrotas().get(j).getLinha());
//				System.out.println("Descrição: "+rotas.get(i).getSubrotas().get(j).getDescricaoLong());
//				System.out.println("Tipo: "+rotas.get(i).getSubrotas().get(j).getTipo());
//				System.out.printf("Tarifa: R$ %.2f\n",rotas.get(i).getSubrotas().get(j).getTarifa());
//				System.out.println("Cor: "+rotas.get(i).getSubrotas().get(j).getCor());
//			}
//		}
		System.out.println("Agente: "+getAID().getName()+" esta fianlizado...");
		
	}
	
	
	

}
